/**
    Copyright (c) 2010 yakiimo02
    Distributed under the New BSD License.
    See included license.txt or http://www.yakiimo3d.com/NewBSDLicense.txt
**/

#include "DXUT.h"
#include "GUI.h"
#include "SmallPtMgr.h"
#include "ToneMapCS.h"
#include "CaptureFrameBuffer.h"

#define IDC_TOGGLEFULLSCREEN    1
#define IDC_TOGGLEREF           3
#define IDC_CHANGEDEVICE        4

// smallpt stuff
#define IDC_SMALLPT_MODE_CB              10000

// tonemap stuff
#define IDC_MIDDLEKEY_TEXT               20001
#define IDC_MIDDLEKEY_SLIDER             20002
#define IDC_TONEMAP_ENABLE_CB            20003
#define IDC_CONTROL_BURNOUT_CB           20004
#define IDC_SAVE_TEXTURE_BTN             20005

#define MIDDLEKEY_SLIDER_MAX             1000


GUI g_gui;

void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );

/**
*/
GUI::GUI() : m_pTxtHelper( NULL ), m_bDisplayGUI( true ), m_pModeCB( NULL ), 
             m_pMiddleKeySlider( NULL ), m_pToneMapEnableCheckBox( NULL ), m_pControlBurnOutCheckBox( NULL ), m_pSaveTextureButton( NULL )
{
}

/**
    @param pd3dDevice    [in]    D3D Device
*/
HRESULT GUI::Create( ID3D11Device* pd3dDevice )
{
    HRESULT hr = S_OK;

    ID3D11DeviceContext* pd3dImmediateContext = DXUTGetD3D11DeviceContext();
    V_RETURN( m_DialogResourceManager.OnD3D11CreateDevice( pd3dDevice, pd3dImmediateContext ) );
    V_RETURN( m_D3DSettingsDlg.OnD3D11CreateDevice( pd3dDevice ) );
    m_pTxtHelper = new CDXUTTextHelper( pd3dDevice, pd3dImmediateContext, &m_DialogResourceManager, 15 );

     return hr;
}

/**
*/
void GUI::RegistGuiItems()
{
    /** General Dialog */

    m_D3DSettingsDlg.Init( &m_DialogResourceManager );
    m_HUD.Init( &m_DialogResourceManager );

    m_HUD.SetCallback( OnGUIEvent ); 
    int nY = 20;
    m_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 0, nY, 170, 23 );
    m_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 0, nY += 26, 170, 23, VK_F3 );
    m_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 0, nY += 26, 170, 23, VK_F2 );

    /** Custom Dialog */

    m_SampleUI.Init( &m_DialogResourceManager );
    m_SampleUI.SetCallback( OnGUIEvent ); 

    /** smallpt stuff */

    // mode combobox
    m_SampleUI.AddComboBox( IDC_SMALLPT_MODE_CB, 0, nY, 150, 24, 'M', false, &m_pModeCB );
    m_pModeCB->AddItem( L"CPU_REF", IntToPtr(SMALLPT_MODE_CPU_REF) );
    m_pModeCB->AddItem( L"CPU_OPT", IntToPtr(SMALLPT_MODE_CPU_OPT) );    
    m_pModeCB->SetSelectedByIndex( g_smallPtMgr.GetMode() );
    m_pModeCB->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;

    /** tonemapping stuff */

    // enable tonemapping checkbox
    m_SampleUI.AddCheckBox( IDC_TONEMAP_ENABLE_CB, L"Tone Mapping", 0, nY, 0, 24, g_toneMapCS.GetToneMapEnable(), 'T', false, &m_pToneMapEnableCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;

    // enable control burnout checkbox
    m_SampleUI.AddCheckBox( IDC_CONTROL_BURNOUT_CB, L"Control BurnOut", 0, nY, 0, 24, g_toneMapCS.GetControlBurnOut(), 'B', false, &m_pControlBurnOutCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;
    
    // middle key slider
    m_SampleUI.AddStatic( IDC_MIDDLEKEY_TEXT, L"Middle Key", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_MIDDLEKEY_SLIDER, 0, nY, 128, 24, 0, MIDDLEKEY_SLIDER_MAX, 300, false, &m_pMiddleKeySlider );
    SetMiddleKeyValue();
    nY += 24;

#if 0
    // save texture button
    m_SampleUI.AddButton( IDC_SAVE_TEXTURE_BTN, L"Save Texture", 0, nY, 150, 24, VK_F5, true, &m_pSaveTextureButton);
    m_pSaveTextureButton->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );    
#endif
}

/**
*/
bool GUI::FrameRender( float fElapsedTime )
{
    // If the settings dialog is being shown, then render it instead of rendering the app's scene
    if( m_D3DSettingsDlg.IsActive() )
    {
        m_D3DSettingsDlg.OnRender( fElapsedTime );
        return true;
    }

    if( m_bDisplayGUI ) {
        DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
        m_HUD.OnRender( fElapsedTime );
        m_SampleUI.OnRender( fElapsedTime );
        RenderText();
        DXUT_EndPerfEvent();
    }

    return false;
}

/**
*/
void GUI::RenderText()
{
    wchar_t strMsg[ 256 ];

    m_pTxtHelper->Begin();
    m_pTxtHelper->SetInsertionPos( 2, 0 );
    m_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
    m_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
    m_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() );

    DataBufferDX11* pDataBufferDX11 = g_smallPtMgr.GetpDataBufferDX11();

    float fFPS = DXUTGetFPS();
    int    nSamplesPerFrame = pDataBufferDX11->GetWidth() * pDataBufferDX11->GetHeight() * 4; 
    float fSamplesPerSecond = fFPS * nSamplesPerFrame;

    // 
    swprintf_s( strMsg, L"Samples/Sec: %f", fSamplesPerSecond );
    m_pTxtHelper->DrawTextLine( strMsg );

    // tonemap
    const MeasureLuminanceCS* pMeasureLuminanceCS = g_toneMapCS.GetpMeasureLuminanceCS();
    swprintf_s( strMsg, L"MiddleKey: %.3f LogAvgLum: %.3f LumMax: %.3f", g_toneMapCS.GetMiddleKey(), pMeasureLuminanceCS->GetLogAvgLum(), pMeasureLuminanceCS->GetLumMax() );
    m_pTxtHelper->DrawTextLine( strMsg );

    // help
    swprintf_s( strMsg, L"Press P=Pause, S=Screenshot, H=Hide GUI", g_toneMapCS.GetMiddleKey(), pMeasureLuminanceCS->GetLogAvgLum(), pMeasureLuminanceCS->GetLumMax() );
    m_pTxtHelper->DrawTextLine( strMsg );

    m_pTxtHelper->End();
}

/**
    @param pd3dDevice        [in]    D3D Device
    @param pBackBufferDesc    [in]    Description of backbuffer
*/
HRESULT GUI::ResizedSwapChain( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc )
{
    HRESULT hr = S_OK;

    V_RETURN( m_DialogResourceManager.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );
    V_RETURN( m_D3DSettingsDlg.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );

    m_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
    m_HUD.SetSize( 170, 170 );
    m_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 350 );
    m_SampleUI.SetSize( 170, 300 );

    return hr;
}

/**
*/
void GUI::Destroy()
{
    m_DialogResourceManager.OnD3D11DestroyDevice();
    m_D3DSettingsDlg.OnD3D11DestroyDevice();
    SAFE_DELETE( m_pTxtHelper );        
}

/**
*/
void GUI::ReleasingSwapChain()
{
    m_DialogResourceManager.OnD3D11ReleasingSwapChain();
}

/**
*/
LRESULT GUI::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
{
    // Pass messages to dialog resource manager calls so GUI state is updated correctly
    *pbNoFurtherProcessing = m_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    // Pass messages to settings dialog if its active
    if( m_D3DSettingsDlg.IsActive() )
    {
        m_D3DSettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
        return 0;
    }

    // Give the dialogs a chance to handle the message first
    *pbNoFurtherProcessing = m_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;
    *pbNoFurtherProcessing = m_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    return 0;
}

/**
    CDXUTDialog callback.
*/
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
    CD3DSettingsDlg& settingsDlg = g_gui.GetrSettingsDlg();

    switch( nControlID )
    {
    case IDC_TOGGLEFULLSCREEN:
        DXUTToggleFullScreen(); 
        break;
    
    case IDC_TOGGLEREF:
        DXUTToggleREF(); 
        break;
    
    case IDC_CHANGEDEVICE:
        settingsDlg.SetActive( !settingsDlg.IsActive() ); 
        break;

    case IDC_SMALLPT_MODE_CB:
        {
            CDXUTComboBox* pComboBox = ( CDXUTComboBox* )pControl;
            g_smallPtMgr.SetMode( static_cast< SmallPtMode >( PtrToInt( pComboBox->GetSelectedData() ) ) );
            // Clear rendered image.
            ID3D11Device* pd3dDevice = DXUTGetD3D11Device();
            const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc = DXUTGetDXGIBackBufferSurfaceDesc();
            g_smallPtMgr.OnResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc, true );
            break;
        }

    // tonemap stuff
    case IDC_MIDDLEKEY_SLIDER:
        {
            //CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_gui.SetMiddleKeyValue();
            break;
        }

    case IDC_TONEMAP_ENABLE_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetToneMapEnable( pCheckBox->GetChecked() );
            break;
        }

    case IDC_CONTROL_BURNOUT_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetControlBurnOut( pCheckBox->GetChecked() );
            break;
        }

    case IDC_SAVE_TEXTURE_BTN:
        {
            g_captureFrameBuffer.Capture( L"smallpt_ss.bmp" );
            break;
        }
    }
}

/**
*/
void GUI::SetMiddleKeyValue()
{
    g_toneMapCS.SetMiddleKey( ( 1.0f*m_pMiddleKeySlider->GetValue() )/MIDDLEKEY_SLIDER_MAX );
}
